Generate Multi-Language Site Using Publish
Generate Multi-Language Site Using Publish
This post talks about how to produce multi-language site using Publish. For example, https://example.com/en/post/title/
and https://example.com/zh/post/title/
for two language versions of the same post, where en
and zh
specifies language.
This feature did not come with standard Website
struct of Publish. It needs some tweaks to make this possible.
What can it do?
- Generate website with posts in different languages in different output path.
- Customize output path for different languages.
- Correlate posts in different languages and make cross links between them.
Basic Usage
Update Swift Package Manager
Since the multi-language feature has not been merged into official repository, you need to change to developing branch in Package.swift
.
1
2
3
4
5
6
7
8
9
let package = Package(
//...
dependencies: [
//...
.package(url: "https://github.com/Ze0nC/Publish", .branch("Multi-Language")),
//...
],
//...
)
Generate Publish Project
Generate a new Publish project if you haven’t got one. Check introduction in official readme. https://github.com/JohnSundell/Publish
If you already have a working Publish project, you may skip this step and modify the existing one.
Setup Your Website
- Modify your website to conform to
MultiLanguageWebsite
instead ofWebsite
. - Add a new variable
var languages: [Language]
, an array of languages your website has. - Modify the
ItemMetadata
to conform toMultiLanguageWebsiteItemMetadata
instead ofWebsiteItemMetadata
. - Add a variable in
ItemMetadata
:var linkID: String?
. - Optional Remove the
var language: Language
variable, or change it to default language of your website.
A modified version of the website that supports English and Chinese would look like below:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// This type acts as the configuration for your website.
struct InternationalWebsite: MultiLanguageWebsite {
// The languages of your website. The first language becomes default language.
var languages: [Language] = [.english, .chinese, .japanese]
enum SectionID: String, WebsiteSectionID {
// Add the sections that you want your website to contain here:
case posts
}
struct ItemMetadata: MultiLanguageWebsiteItemMetadata {
// A metadata entry to correlate posts in different languages.
var linkID: String?
// Add any site-specific metadata that you want to use here.
}
// Update these properties to configure your website:
var url = URL(string: "https://your-website-url.com")!
var name = "InternationalWebsite
var description = "A description of InternationalWebsite"
var imagePath: Path? { nil }
}
Arrange Markdown Files
By default, the markdown files for posts are located in ‘Content’ folder, with the following structure:
1
2
3
4
5
6
Content/
SectionOne/
PostOne.md
PostTwo.md
SectionTwo/
PostThree.md
Change the above structure and make a folder for each language, where the folder name is language code of the language. You may find a list of supported languages in Language.swift
of Plot.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
en/
SectionOne/
PostOne.md
PostTwo.md
SectionTwo/
PostThree.md
zh/
SectionOne/
PostOne.md
PostTwo.md
SectionTwo/
PostThree.md
ja/
SectionOne/
PostOne.md
PostTwo.md
SectionTwo/
PostThree.md
Localize Theme
Localize the Theme you are using to show different versions for languages.
For example, the makeIndexHTML()
becomes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
func makeIndexHTML(for index: Index,
context: PublishingContext<Site>) throws -> HTML {
HTML(
.lang(index.language!), // Use language of the index.
.head(for: index, on: context.site),
.body(
.header(for: context, selectedSection: nil),
.wrapper(
.h1(.text(index.title)),
.p(
.class("description"),
.text(context.site.description)
),
.h2("Latest content"),
.itemList(
for: context.allItems(
sortedBy: \.date,
in: index.language!, // Get items in the specific language only.
order: .descending
),
on: context.site
)
),
.footer(for: context.site)
)
)
}
You may need to localize the text of the website, e.g. section names, links, etc.
It is the time to use your creativity to make your own website localized.
More Usage
Customize the name of content folder name of each language.
By default, Publish process markdown files of each language located in folder named by language code, e.g. en, zh, etc. To change it, implement the following method of your website:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
extension InternationalWebsite {
func contentFolder(for language: Language) -> String {
switch language {
case .english:
return "English Content" // "en" by default
case .chinese:
return "Chinese Content" // "zh" by default
case .japanese:
return "Japanese Content" // "ja" by default
default:
return language.rawValue
}
}
}
Customize the language component of output path.
By default, Publish outputs html files of each language located in folder named by language code, e.g. en, zh, etc. To change it, implement the following method of your website:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
extension InternationalWebsite {
func pathPrefix(for language: Language) -> String {
switch language {
case .english:
return "us" // "en" by default
case .chinese:
return "cn" // "zh" by default
case .japanese:
return "jp" // "ja" by default
default:
return language.rawValue
}
}
}
Specify the language of markdown file.
You may specify then language of markdown file by setting language
to language code in metadata.
1
2
3
---
language: en
---
Correlate markdown files in different languages
By default, markdown files with the same path are considered as language variations of the same item. If you want to correlate markdown files with different file name, e.g.
- en/Section/example.md in English
- zh/Section/样例.md in Chinese
- ja/Section/例.md in Japanese
You need to correlate them by setting linkID
to the same value in metadata of the above files.
1
2
3
---
linkID: example-markdown
---